依存関係フローグラフの例

次の例では、A-E の 5 つの計算が下記の 「単純な依存関係グラフ」 のように半順序でセットアップされています。フローグラフの各エッジで、エッジの最後のノードは先頭のノードが開始する前に実行を完了していなければなりません。

./picture/dep_graph.jpg

単純な依存関係グラフ


#include <cstdio> 
#include "oneapi/tbb/flow_graph.h" 

using namespace oneapi::tbb::flow; 

struct body { 
    std::string my_name; 
    body(const char *name) : my_name(name) {} 
    void operator()(continue_msg) const { 
        printf("%s\n", my_name.c_str()); 
    } 
};
 
int main() { 
    graph g; 

    broadcast_node< continue_msg > start(g); 
    continue_node<continue_msg> a(g, body("A")); 
    continue_node<continue_msg> b(g, body("B")); 
    continue_node<continue_msg> c(g, body("C")); 
    continue_node<continue_msg> d(g, body("D")); 
    continue_node<continue_msg> e(g, body("E")); 

    make_edge(start, a); 
    make_edge(start, b); 
    make_edge(a, c); 
    make_edge(b, c); 
    make_edge(c, d); 
    make_edge(a, e); 

    for (int i = 0; i < 3; ++i) { 
        start.try_put(continue_msg()); 
        g.wait_for_all(); 
    } 

    return 0; 
}

この例では、ノード A-E がそれぞれの名前を出力します。そのため、これらのノードはすべて struct body を使用してボディー・オブジェクトを構築できます。

main 関数で、フローグラフは一回セットアップされ、3 回実行されます。この例のノードはすべて、continue_msg オブジェクトを使用します。このタイプは、ノードが実行完了したことを通知するために使用されます。

main 関数の最初の行は、graph オブジェクト g をインスタンス化します。次の行で、start という名称の broadcast_node を作成しています。このノードに渡されるものはすべて、その後続 (サクセサー) にブロードキャストされます。start ノードは、main の最後にある for ループで残りのフローグラフを実行するために使用されます。

この例では、名前が a - e の 5 つの continue_node オブジェクトが作成されます。各ノードは、graph g への参照と、実行時に呼び出す関数オブジェクトにより構築されます。後続 (サクセサー) / 先行 (プリディセッサー) の関係は、ノードの宣言に続く make_edge 呼び出しでセットアップされます。

ノードとエッジが設定された後、for ループのそれぞれの反復で try_put によって、ab の両方に continue_msg がブロードキャストされます。ab のどちらも単一の continue_msg を持っています。これは、どちらも先行する start しか持たないためです。

start からメッセージを受け取ると、ボディー・オブジェクトを実行します。完了すると、それぞれがサクセサーにメッセージを転送します。計算を並列に実行可能な場合、グラフは複数のタスクを使用してノード間でメッセージを送る処理と、ノードのボディーを実行する処理を並列に実行します。

参照: